import Watcher from "./observe/watcher";
import { patch } from "./vdom/patch";

export function lifeCycleMixin(Vue) {
  // console.log('lifeCycleMixin')
  Vue.prototype._update = function (vnode) {
    const vm = this;

    // // 将虚拟 DOM 转换成真实 DOM ，将当前的节点替换掉以前的节点
    // vm.$el = patch(vm.$el, vnode); // 虚拟节点（vnode）创建出真实节点，替换真实节点（vm.$el, div id="app"）

    // 优化不直接 patch， 判断是否有上一次的 vnode
    const prevVnode = vm._vnode; // 上一次 vnode，更新的时候检测是否可以复用
    if (!prevVnode) {
      // 将虚拟 DOM 转换成真实 DOM ，将当前的节点替换掉以前的节点
      vm.$el = patch(vm.$el, vnode); // 虚拟节点（vnode）创建出真实节点，替换真实节点（vm.$el, div id="app"）     
    } else {
      vm.$el = patch(prevVnode, vnode);
    }

    vm._vnode = vnode; // 渲染结束，更新上一次的 vnode 为当前的 vnode
  }
}

/**
 * 挂在组件入口
 * @param {*} vm vdom
 * @param {*} el elment
 */
export function mountComponent(vm, el) {
  // console.log('mountComponent');
  vm.$el = el; // 挂载一下真实 DOM，后续使用
  const options = vm.$options;

  // 渲染页面，无论是渲染还是更新都会要调用该函数
  const updateComponent = () => { // 数据变化，也调用这个函数执行
    const vnode = vm._render(); // 调用 render 方法返回的虚拟 DOM
    vm._update(vnode); // 将虚拟 DOM 转换成真实 DOM
  }

  // 观察者模式 + 依赖搜集 + diff 算法，去更新组件
  // updateComponent();

  // 为了做依赖收集，让渲染 Watcher 去调用 updateComponent() 函数更新视图
  // 渲染 watcher 每个组件都对应一个 watcher (响应式的，每次数据变化都会调用 updateComponent 方法)
  // () => {}： 表示调用 vm.$watch(), true：表示是一个渲染 Watcher
  new Watcher(vm, updateComponent, () => {
    console.log("视图重新渲染");
  }, true);
}

// 生命周期函数
export function callHook(vm, hook) {
  const handlers = vm.$options[hook];
  if (handlers) {
    handlers.forEach(handler => {
      handler.call(vm);
    });
  }
}